﻿using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Networking;

public class Weapon : Item
{
    public float attackRange = 1f;
    public float damage = 1f;
    protected Effect damageEffect;
    public float energyConsumption = 1f;
    public float impact;
    [SerializeField, SyncVar]
    private ushort m_durability;
    public float maxDurability;
    public LayerMask targetLayerMask;
    public GameTagMask targetTagMask;

    public virtual bool ApplyDamage(Character attacker, Character target)
    {
        return CombatUtility.ApplyDamage(attacker, target, this.damage);
    }

    public virtual bool ApplyImpact(Character target, Vector3 hitNormal)
    {
        if (this.impact == 0f)
        {
            return false;
        }
        return CombatUtility.ApplyImpact(target, (Vector3) (-hitNormal.normalized * this.impact));
    }

    protected override void Awake()
    {
        base.Awake();
        this.damageEffect = GameResources.Effects.Damage;
        this.targetLayerMask = (LayerMask) (((GameLayers.Wall | GameLayers.Character) | GameLayers.Obstacle) | GameLayers.Floor);
        this.durability = this.maxDurability;
    }

    public void ConsumeUserEnergy()
    {
        if (base.user != null)
        {
            base.user.energy -= this.energyConsumption;
        }
    }

    public virtual bool Hit(Character attacker, Character target, Vector3 hitPoint, Vector3 hitNormal)
    {
        if (target == null)
        {
            return false;
        }
        if (!this.targetTagMask.IsMasked(target.tag))
        {
            return false;
        }
        if (target.life == null)
        {
            return false;
        }
        if (attacker == null)
        {
            return false;
        }
        bool flag = false;
        IWeaponHitHandler component = attacker.GetComponent(typeof(IWeaponHitHandler)) as IWeaponHitHandler;
        if (component != null)
        {
            flag = component.HandleWeaponHit(this, attacker, target, hitPoint, hitNormal);
        }
        else
        {
            flag = this.ApplyDamage(attacker, target);
            this.ApplyImpact(target, hitNormal);
        }
        if (flag)
        {
            this.SpawnDamageEffect(target, hitPoint, hitNormal);
        }
        return flag;
    }

    public override void OnDeserialize(NetworkReader reader, bool initialState)
    {
        base.OnDeserialize(reader, initialState);
        if (initialState)
        {
            this.m_durability = (ushort) reader.ReadPackedUInt32();
        }
        else if ((reader.ReadPackedUInt32() & 1) != 0)
        {
            this.m_durability = (ushort) reader.ReadPackedUInt32();
        }
    }

    public override bool OnSerialize(NetworkWriter writer, bool forceAll)
    {
        bool flag2 = base.OnSerialize(writer, forceAll);
        if (forceAll)
        {
            writer.WritePackedUInt32(this.m_durability);
            return true;
        }
        bool flag = false;
        if ((base.syncVarDirtyBits & 1) != 0)
        {
            if (!flag)
            {
                writer.WritePackedUInt32(base.syncVarDirtyBits);
                flag = true;
            }
            writer.WritePackedUInt32(this.m_durability);
        }
        if (!flag)
        {
            writer.WritePackedUInt32(base.syncVarDirtyBits);
        }
        return (flag | flag2);
    }

    public virtual void SpawnDamageEffect(Character target, Vector3 hitPoint, Vector3 hitNormal)
    {
        if (this.damageEffect != null)
        {
            this.damageEffect.Spawn<Effect>(hitPoint, Quaternion.LookRotation(-hitNormal.normalized));
        }
    }

    private void UNetVersion()
    {
    }

    public override bool canUse
    {
        get
        {
            if (this.isBroken)
            {
                return false;
            }
            if ((base.user != null) && !base.user.HasEnergy(this.energyConsumption))
            {
                return false;
            }
            return base.canUse;
        }
    }

    public float durability
    {
        get
        {
            return (float) this.m_durability;
        }
        set
        {
            value = Mathf.Clamp(value, 0f, this.maxDurability);
            this.Networkm_durability = (ushort) value;
        }
    }

    private bool hasDurability
    {
        get
        {
            return (!this.isInfinteDurability ? (this.durability > 0f) : true);
        }
    }

    public bool isBroken
    {
        get
        {
            return !this.hasDurability;
        }
    }

    public bool isInfinteDurability
    {
        get
        {
            return (this.maxDurability <= 0f);
        }
    }

    public ushort Networkm_durability
    {
        get
        {
            return this.m_durability;
        }
        [param: In]
        set
        {
            base.SetSyncVar<ushort>(value, ref this.m_durability, 1);
        }
    }
}

